using Game.Networking.Server;
using System.Collections.Generic;
using UnityEngine;

namespace Game {
	public class ShipAPI : IShipAPI {
		ShipPhysics _physics;
		ShipCore    _core;

		public ShipAPI(ShipCore core, ShipPhysics physics) {
			_core= core;
			_physics = physics;
		}

		public Vector3 ShipPosition => _core.transform.position;
		public Vector3 EulerAngles => _core.transform.rotation.eulerAngles;
		public float   Velocity => _physics.Velocity;
		public float   DistanceToAutopilotTarget => Vector3.Distance(_core.transform.position, TargetPoint);

		public float ThrustLimit {
			get => _physics.ThrustLimit;
			set {
				_physics.ThrustLimit = Mathf.Clamp01(value);
			}
		}

		public float SpeedLimit {
			get => _physics.SpeedLimit;
			set {
				_physics.SpeedLimit = Mathf.Clamp(value, 0, _physics.MaxVelocity);
			}
		}

		public IRadar  Radar => _core.Radar;
		public IReactor  Reactor => _core.Reactor;

		public ISignalReceiver SignalReceiver => _core.SignalReceiver;

		public TeamType Team => _core.Team;

		public Vector3 TargetPoint {
			get {
				return _physics.MoveTarget;
			}
			set {
				_physics.MoveTarget = value;
			}
		}

		public int Health => _core.Health;

		public void SetTargetPoint(float x, float y, float z) {
			_physics.MoveTarget = new Vector3(x, y, z);
		}

		public bool IsLookingAtTarget() {
			var toTarget = (_physics.MoveTarget - _core.transform.position).normalized;
			var forward = _core.transform.TransformDirection(Vector3.forward);
			if ( Vector3.Dot(toTarget, forward) > 0.9f ) {
				return true;
			}
			return false;
		}

		public bool AttitudeAutopilotEnabled {
			get => _physics.Enabled;
			set => _physics.Enabled = value;
		}

		public void SetShipControls(float pitch, float yaw, float roll, float thrust) {
			_physics.Pitch  = Mathf.Clamp(pitch,  -1f, 1f);
			_physics.Yaw    = Mathf.Clamp(yaw,    -1f, 1f);
			_physics.Roll   = Mathf.Clamp(roll,   -1f, 1f);
			_physics.Thrust = Mathf.Clamp(thrust, -1f, 1f);
		}

		public Vector4 GetShipControlInputs() {
			return new Vector4(_physics.Pitch, _physics.Yaw, _physics.Roll, _physics.Thrust);
		}

		public bool ThrustAutopilotEnabled {
			get => _physics.ThrustAutopilot;
			set {
				if ( !value ) {
					_physics.Thrust = 0f;
				}
				_physics.ThrustAutopilot = value;
			}
		}

		public bool CollisionAvoidanceEnabled {
			get => _physics.EnableCollisionAvoidance; set => _physics.EnableCollisionAvoidance = value;
		}
		
		public bool ShootGun() {
			return _core.TryShootGun();
		}

		public bool CollectItem(EntitySummary item) {
			return _core.Cargo.TryCollectItem(item);
		}

		public bool CollectItem(uint itemId) {
			return _core.Cargo.TryCollectItem(itemId);
		}

		public int CollectAllCargo() {
			return _core.CollectAllCargo();
		}

		public void DropAllCargo() {
			_core.DropAllCargo();
		}

		public int GetInventoryTotalItemsCount() {
			return _core.Cargo.Inventory.ItemCount;
		}

		public int GetInventoryFreeSlotsCount() {
			return _core.Cargo.Inventory.FreeSlotsCount;
		}

		public int GetInventoryCapacity() {
			return _core.Cargo.Inventory.SlotCount;
		}

		public int GetInventoryOccupiedSlotsCount() {
			return _core.Cargo.Inventory.OccupiedSlotsCount;
		}

		public InventoryItemDescription GetInventorySlotInfo(int slotIndex) {
			return _core.Cargo.GetInventorySlotInfo(slotIndex);
		}

		public void Jump(Vector3 direction) {
			_physics.Jump(direction);
		}

		public Vector3 DirectionLocalToGlobal(Vector3 direction) {
			return _core.transform.TransformDirection(direction);
		}

		public bool CraftMissile() {
			return _core.Cargo.CraftMissile();
		}

		public bool LaunchMissile(uint targetId) {
			return _core.TryLaunchMissile(targetId);
		}

		public void DropFromSlot(int slot) {
			_core.Cargo.TryDropFromSlot(slot);
		}

		public void DropFromSlot(int slot, int count) {
			_core.Cargo.TryDropFromSlot(slot, count);
		}

		public List<InventoryItemDescription> GetAllInventoryItems() {
			return _core.Cargo.GetInventorySlotsInfo();
		}

		public int GetInventoryTotalPrice() {
			return _core.Cargo.Inventory.GetWholeInventoryPrice();
		}

		public void BreakCoroutine() {
			var unitId = ServerAgentsController.Instance.GetAgentEntityOwnerUnitId(_core.ID);
			if ( unitId == 0 ) {
				return;
			}
			var unit = ServerScriptController.Instance.GetUnitById(unitId);
			if ( unit == null ) {
				return;
			}
			unit.BreakCoroutine();
		}
	}
}
